package com.liyong.pullorder.channels.http;

import com.liyong.pullorder.channels.autoconfigure.ChannelsPullProperties;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;

import java.nio.charset.StandardCharsets;

@Slf4j
/**
 * HTTP 客户端提供器。
 *
 * 作用：
 * - 暴露带连接池的 `CloseableHttpClient` 与基于其的 `RestTemplate`。
 * - 统一设置超时与连接池参数，确保渠道拉单在高并发下稳定。
 * - 设置 UTF-8 字符编码，避免中文乱码与跨平台编码问题。
 */
public class HttpClientProvider {
    private final ChannelsPullProperties properties;

    public HttpClientProvider(ChannelsPullProperties properties) {
        this.properties = properties;
    }

    /**
     * 创建基于连接池 HTTP 客户端的 RestTemplate。
     *
     * 细节：
     * - 注入 UTF-8 `StringHttpMessageConverter` 到首位，保证字符串编码一致。
     * - 使用统一的 `clientHttpRequestFactory()` 承载超时与连接池配置。
     */
    public RestTemplate restTemplate() {
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory());
        restTemplate.getMessageConverters().add(0, new StringHttpMessageConverter(StandardCharsets.UTF_8));
        return restTemplate;
    }

    /**
     * 创建 `HttpComponentsClientHttpRequestFactory` 并设置统一参数。
     *
     * 参数说明：
     * - `connectionRequestTimeout`：从连接池获取连接的最大等待时间。
     * - `connectTimeout`：建立 TCP 连接的超时时间。
     * - `readTimeout`：读取数据（SO_TIMEOUT）的超时时间。
     */
    public HttpComponentsClientHttpRequestFactory clientHttpRequestFactory() {
        HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory();
        factory.setHttpClient(httpClient());
        factory.setConnectionRequestTimeout(properties.getHttpClient().getConnectionRequestTimeout());
        factory.setConnectTimeout(properties.getHttpClient().getConnectTimeout());
        factory.setReadTimeout(properties.getHttpClient().getSocketTimeout());
        return factory;
    }

    /**
     * 创建带连接池的 `CloseableHttpClient`。
     *
     * 连接池策略：
     * - `maxTotal`：连接池最大连接数（所有路由总和）。
     * - `maxPerRoute`：单路由最大并发连接数。
     *
     * 注意：
     * - 若存在大量不同平台/域名，`maxPerRoute` 需要按热点路由适当调高。
     */
    private CloseableHttpClient httpClient() {
        RequestConfig requestConfig = RequestConfig.custom()
                .setConnectTimeout(properties.getHttpClient().getConnectTimeout())
                .setSocketTimeout(properties.getHttpClient().getSocketTimeout())
                .setConnectionRequestTimeout(properties.getHttpClient().getConnectionRequestTimeout())
                .build();

        PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setMaxTotal(properties.getHttpClient().getMaxTotal());
        connectionManager.setDefaultMaxPerRoute(properties.getHttpClient().getMaxPerRoute());

        return HttpClients.custom()
                .setConnectionManager(connectionManager)
                .setDefaultRequestConfig(requestConfig)
                .build();
    }
}